//------------------------------------------------------------------------
// Cube Monitoring Tool
//------------------------------------------------------------------------
#include <iostream>

#include "property/CProperty.h"

#include "CDiscoveryProxy.h"
#include "CSpaceMonitorThread.h"

using namespace std;


void print_instance_detail(char *ip, int port, char *service_name, char *instance)
{
	cout << service_name << "(" << instance << ")";

	// in case of space service
	if(!strcmp(service_name, CUBE_SERVICE_SPACE)) {
	//if(!strcmp(service_name, CUBE_SERVICE_SPACE)) {
		CSpaceMonitorThread mon(service_name);
		if(instance==NULL) mon.workspace(service_name, service_name);
		else mon.workspace(service_name, instance);
		mon.add(ip, port);

		mon.start();
		mon.join();

		cout << " = " << mon.size();
	}

	cout << endl;
}

void print_instances(char *ip, int port, char *service_name)
{
	CObjectArray *pobjs = NULL;
	cube__CService *instance_request = NULL;
	struct cube__invokeResponse res;

	CServiceProxy proxy;
	proxy.connect(ip, port);

	if(proxy.invoke(instance_request, pobjs, res)!=SOAP_OK) {
		//soap_print_fault(proxy.soap(), stderr);
		return;
	}

	CObjectArray *robjs = dynamic_cast<CObjectArray *>(res.out);
	if(robjs==NULL) return;

	for(int i=0;i<robjs->__size;i++) {
		cube__CKeyValue *kv = dynamic_cast<cube__CKeyValue *>(robjs->__ptr[i]);

		if(!strcmp(service_name,kv->getKey())) {
			cout << "    +";
			print_instance_detail(ip, port, kv->getKey(), kv->getValue());
		}
	}

	if(pobjs!=NULL) delete pobjs;
}

int main(int argc, char **argv)
{
	if(argc<2) {
		cout << "Usage: " << argv[0] << " [-c <conf> or -h <ip> -p <port>] [-s <service>] [-i <instance>]" << endl;
		exit(-1);
	}

	int opt;
	static char optstr[] = "chpsi";

	char *conf = "coord.conf";
	string host = "";
	int port = -1;
	char *service = NULL;
	char *instance = NULL;

	while((opt=getopt(argc,argv,optstr))!=-1) {
		switch(opt) {
			case 'c' :
			{
				conf = argv[optind++];
				CProperty config(conf);
				pair<string,string> kv;
				kv.first = COORD_CONF_MASTER_IP_KEY;
				host = config.get(kv).second;
				kv.first = COORD_CONF_MASTER_PORT_KEY;
				port = atoi((char *)config.get(kv).second.c_str());
				break;
			}
			case 'h' :
				host = argv[optind++];
				break;
			case 'p' :
				port = atoi(argv[optind++]);
				break;
			case 's' :
				service = argv[optind++];
				break;
			case 'i' :
				instance = argv[optind++];
				break;
		}
	}	

	while(1) {
		char *discovery_ip = (char *)host.c_str();
		int discovery_port = port;

		CDiscoveryProxy discovery(discovery_ip, discovery_port);

		vector<CServiceInfo> services;
		services = discovery.discover(NULL);
		

		// clear screen
		fprintf(stdout, "\033[2J");
		fprintf(stdout, "\033[1;1H");

		cout << "============================================================================================\n";
		cout << "\t<host>\t\t<cpu>\t  <load>\t<service>" << endl;
		cout << "============================================================================================\n";

		for(int i=0, k=0;i<services.size();i++) {
			char *service_name = services[i].getName();

			if(i==0) cout << "[" << k << "]";
			else if(strcmp(services[i-1].getIP(), services[i].getIP())||
				services[i-1].getPort()!=services[i].getPort()) cout << "[" << ++k << "]";
			else cout << "[" << k << "]";

			cout << services[i].getIP() << ":";
			cout << services[i].getPort() << "\t";

			cout << services[i].getCPU() << "\t  ";
			cout << services[i].getLoad() << "\t    ";
			cout << service_name;

			cout << endl;

			print_instances(services[i].getIP(), services[i].getPort(), service_name);
		}
	
		sleep(3);
	}

	return 0;
}
